package com.yilin.platform.base_core.tools;

import com.baomidou.mybatisplus.annotation.EnumValue;
import com.google.gson.reflect.TypeToken;
import com.yilin.platform.base_core.commons.utils.JsonUtil;
import com.yilin.platform.base_core.commons.utils.StringUtil;
import com.yilin.platform.base_core.components.redis.RedisClient;
import com.yilin.platform.base_core.components.redis.RedisKeys;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 短信工具类 创 建 人： 武国庆 日 期： 2016年6月15日 下午8:00:35 修 改 人： 日 期： 描 述： 版 本 号： V1.0
 */
public class SMSUtil {

    public static final String SUCCESS = "success";//返回成功与标志
    public static final String SURPLUS_SECOND = "surplusSecond"; // 发送验证码剩余时间
    public static final String MSG = "msg";//返回信息

    public static final String TIME = "time"; // 验证码创建时间
    private static final String ELAPSE_TIME = "elapseTime"; // 验证码已经存在了多少时间
    private static final String CODE = "code"; // 验证码
    private static final String ERR_COUNT = "errCount";//错误次数

    public static enum MsgType {
        phoneCode(0,"普通手机验证码"),
        organizeRegister(1,"组织注册验证码"),
        employeeRegister(2,"员工注册验证码"),
        phoneLogin(3,"手机号快速登录"),
        updatePassword(4,"修改密码"),
        updateSafePassword(5,"修改安全密码"),
        bindBankcard(6,"绑定银行卡"),
        deliveryPromise(7,"发货合同确认"),
        trafficPromise(8,"起运合同确认"),
        arriveCode(9,"货物签收验证码");

        @EnumValue
        public Integer index;
        public String name;

        MsgType(Integer index, String name) {
            this.index = index;
            this.name = name;
        }
    }

    //获取验证码倒计时
    public static Map<String, Object> canSendCodeNew(String phone, MsgType msgType) {
        Map<String, Object> map = new HashMap<>();
        RedisClient redisClient = RedisClient.getInstance();
        String field = getPhoneField(phone, msgType);
        long time = System.currentTimeMillis();
        long elapseTime = 0;
        long surplusSecond = 60;
        boolean success = false;
        do {
            String value = redisClient.hget(RedisKeys.MESSAGE_SEND_CODE_KEY, field);
            if (StringUtil.isEmpty(value)) {
                surplusSecond = 0;
                success = true;
                break;
            }
            Map<String, Object> memMap = JsonUtil.jsonToObject(value, new TypeToken<Map<String, Object>>() {});
            String str = memMap.get(SMSUtil.TIME).toString();
            time = Long.parseLong(new BigDecimal(str).toPlainString());
            elapseTime = System.currentTimeMillis() - time;
            surplusSecond = Math.max(0, 60 - (elapseTime / 1000));
            success = surplusSecond == 0;

        } while (false);
        map.put(SUCCESS, success);
        map.put(TIME, time);
        map.put(ELAPSE_TIME, elapseTime);
        map.put(SURPLUS_SECOND, surplusSecond);
        map.put(CODE, "");
        return map;
    }

    //保存并发送验证码
    public static Map<String, Object> saveCashCode(String phone, String code, MsgType msgType) {
        RedisClient redisClient = RedisClient.getInstance();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put(SUCCESS, false);
        map.put(TIME, System.currentTimeMillis());
        map.put(ELAPSE_TIME, 0);
        map.put(SURPLUS_SECOND, 60);
        map.put(CODE, code);
        String field = getPhoneField(phone, msgType);
        String json = JsonUtil.objectToJson(map);
        redisClient.hset(RedisKeys.MESSAGE_SEND_CODE_KEY, field, json);
        map.put(CODE, "");
        return map;
    }

    //验证验证码-验证后删除
    public static Map<String, Object> verifyCode(String phone, String code, MsgType msgType) {
        return verifyCode(phone,code,msgType,true);
    }

    //验证验证码
    public static Map<String, Object> verifyCode(String phone, String code, MsgType msgType, boolean deleteCode) {
        RedisClient redisClient = RedisClient.getInstance();
        Map<String, Object> retMap = new HashMap<>();
        Map<String, Object> codeMap = getSendCodeMap(phone, msgType);
        String result = (codeMap == null ? null : codeMap.get(SMSUtil.CODE).toString());
        if (StringUtil.isEmpty(result)) {
            retMap.put(SUCCESS, false);
            retMap.put(MSG, "验证码不存在，请重新发送验证码！");
            return retMap;
        }
        String str = codeMap.get(SMSUtil.TIME).toString();
        if (StringUtil.isEmpty(str)) {
            retMap.put(SUCCESS, false);
            retMap.put(MSG, "验证码不存在，请重新发送验证码！");
            return retMap;
        }
        long time = Long.parseLong(new BigDecimal(str).toPlainString());
        long elapseTime = System.currentTimeMillis() - time;
        long surplusElapseSecond = Math.max(0, 60*10 - (elapseTime / 1000));
        if (surplusElapseSecond <= 0 ) {
            retMap.put(SUCCESS, false);
            retMap.put(MSG, "验证码已过期，请重新发送验证码！");
            deleteSendCode( phone,  msgType);
            return retMap;
        }
        if (!result.equals(code)) {
            if (codeMap.containsKey(ERR_COUNT)) {
                Object o = codeMap.get(ERR_COUNT);
                int errCount;
                if (o instanceof Double){
                    errCount =(int) ((Double) codeMap.get(ERR_COUNT)).doubleValue();
                }else {
                    errCount = (int) codeMap.get(ERR_COUNT);
                }
                if (errCount > 3) {
                    deleteSendCode(phone, msgType);
                    retMap.put(SUCCESS, false);
                    retMap.put(MSG, "您输入的验证码错误次数过多，请重新发送！");
                    return retMap;
                }
                errCount += 1;
                codeMap.put(ERR_COUNT, errCount);
            } else {
                codeMap.put(ERR_COUNT, 1);
            }
            String json = JsonUtil.objectToJson(codeMap);
            String field = getPhoneField(phone, msgType);
            redisClient.hset(RedisKeys.MESSAGE_SEND_CODE_KEY, field, json);
            retMap.put(SUCCESS, false);
            retMap.put(MSG, "验证码错误，请重新输入验证码！");
            return retMap;
        }
        //验证成功
        if (deleteCode) deleteSendCode(phone, msgType);
        retMap.put(SUCCESS, true);
        retMap.put(MSG, "验证码验证成功！");
        return retMap;
    }

    //自动删除： 获取对应的Field键值和对应的时间
    public static Map<String, Long> getAllSendCodeMapTime() {
        Map<Object, Object> map = RedisClient.getInstance().hEntries(RedisKeys.MESSAGE_SEND_CODE_KEY);
        Map<String,Long> accessMap = new HashMap<>();
        for (Object key : map.keySet()){
            if (map.get(key)==null) continue;
            Map<String, Object> codeMap = JsonUtil.jsonToObject(map.get(key).toString(), new TypeToken<Map<String, Object>>() {});
            long aLong = (long) codeMap.get(SMSUtil.TIME);
            accessMap.put(key.toString(),aLong);
        }
        return accessMap;
    }

    //获取发的验证码
    private static Map<String, Object> getSendCodeMap(String phone, MsgType msgType) {
        RedisClient redisClient = RedisClient.getInstance();
        String field = getPhoneField(phone, msgType);
        String value = redisClient.hget(RedisKeys.MESSAGE_SEND_CODE_KEY, field);
        if (StringUtil.isEmpty(value)) return null;
        return JsonUtil.jsonToObject(value, new TypeToken<Map<String, Object>>() {});
    }

    //删除验证码 验证成功、过期、错误过多都要删除验证码
    public static void deleteSendCode(String phone,  MsgType msgType) {
        String key = getPhoneField(phone, msgType);
        deleteSendCode( key);
    }

    public static void deleteSendCode(String key) {
        RedisClient redisClient = RedisClient.getInstance();
        redisClient.hdel(RedisKeys.MESSAGE_SEND_CODE_KEY,key);
    }

    //内部：Redis键值构造方式 唯一
    private static String getPhoneField(String phone, MsgType msgType) {
        return msgType.toString() +"_"+ phone;
    }

}